// Exception Handling (异常处理) 示例
// 演示 Pascal 中异常处理的各种用法
program p_25_exception_handling;

{$mode objfpc}{$H+}
// {$mode objfpc} 启用 Object Pascal 模式，支持异常处理
// {$H+} 启用长字符串支持（AnsiString）

// 引入单元文件
uses
  SysUtils;  // 系统工具单元，包含异常类和处理函数

// 自定义异常类型
type
  ECustomError = class(Exception)
  end;
  
  EMathError = class(Exception)
  end;

// 演示除零异常的函数
function DivideNumbers(dividend, divisor: Real): Real;
begin
  if divisor = 0 then
    raise EZeroDivide.Create('除数不能为零')
  else
    DivideNumbers := dividend / divisor;
end;

// 演示自定义异常的过程
procedure CheckPositiveNumber(value: Integer);
begin
  if value <= 0 then
    raise ECustomError.Create('数值必须为正数，当前值: ' + IntToStr(value));
end;

// 演示文件操作异常的过程
procedure ReadFromFile(filename: String);
var
  fileVar: Text;
begin
  Assign(fileVar, filename);
  Reset(fileVar);
  // 实际文件操作代码...
  Close(fileVar);
end;

// 演示基本异常处理
procedure DemonstrateBasicExceptionHandling;
var
  result: Real;
begin
  WriteLn('  基本异常处理演示:');
  
  try
    result := DivideNumbers(10, 0);  // 这会引发除零异常
    WriteLn('    结果: ', result:0:2);
  except
    on E: EZeroDivide do
      WriteLn('    捕获到除零异常: ', E.Message);
    on E: Exception do
      WriteLn('    捕获到其他异常: ', E.ClassName, ' - ', E.Message);
  end;
end;

// 演示自定义异常处理
procedure DemonstrateCustomExceptionHandling;
begin
  WriteLn('  自定义异常处理演示:');
  
  try
    CheckPositiveNumber(-5);  // 这会引发自定义异常
  except
    on E: ECustomError do
      WriteLn('    捕获到自定义异常: ', E.Message);
    on E: Exception do
      WriteLn('    捕获到其他异常: ', E.ClassName, ' - ', E.Message);
  end;
end;

// 演示文件异常处理
procedure DemonstrateFileExceptionHandling;
begin
  WriteLn('  文件异常处理演示:');
  
  try
    ReadFromFile('nonexistent.txt');  // 这会引发文件未找到异常
  except
    on E: EInOutError do
      WriteLn('    文件输入输出错误: ', E.Message);
    on E: EFileNotFound do
      WriteLn('    文件未找到: ', E.Message);
    on E: Exception do
      WriteLn('    其他文件相关异常: ', E.ClassName, ' - ', E.Message);
  end;
end;

// 演示finally块的使用
procedure DemonstrateFinallyBlock;
var
  fileVar: Text;
begin
  WriteLn('  Finally块演示:');
  
  Assign(fileVar, 'test.txt');
  try
    Rewrite(fileVar);
    WriteLn(fileVar, '测试数据');
    WriteLn('    文件写入成功');
  except
    on E: Exception do
      WriteLn('    文件操作异常: ', E.Message);
  finally
    // 无论是否发生异常，都会执行这里的代码
    if FileExists('test.txt') then
    begin
      Close(fileVar);
      Erase(fileVar);
      WriteLn('    文件已清理');
    end;
  end;
end;

// 演示异常传播
procedure Level3Procedure;
begin
  WriteLn('      第3级过程 - 引发异常');
  raise Exception.Create('这是在第3级过程中引发的异常');
end;

procedure Level2Procedure;
begin
  WriteLn('    第2级过程 - 调用第3级过程');
  Level3Procedure;
end;

procedure Level1Procedure;
begin
  WriteLn('  第1级过程 - 调用第2级过程');
  try
    Level2Procedure;
  except
    on E: Exception do
    begin
      WriteLn('  第1级过程 - 捕获并重新引发异常');
      raise;  // 重新引发异常
    end;
  end;
end;

procedure DemonstrateExceptionPropagation;
begin
  WriteLn('  异常传播演示:');
  try
    Level1Procedure;
  except
    on E: Exception do
      WriteLn('  主程序 - 捕获传播的异常: ', E.Message);
  end;
end;

// 程序主入口
begin
  WriteLn('=== Pascal 异常处理示例 ===');
  WriteLn;
  
  // 1. 基本异常处理
  WriteLn('1. 基本异常处理:');
  DemonstrateBasicExceptionHandling;
  
  WriteLn;
  
  // 2. 自定义异常处理
  WriteLn('2. 自定义异常处理:');
  DemonstrateCustomExceptionHandling;
  
  WriteLn;
  
  // 3. 文件异常处理
  WriteLn('3. 文件异常处理:');
  DemonstrateFileExceptionHandling;
  
  WriteLn;
  
  // 4. Finally块使用
  WriteLn('4. Finally块使用:');
  DemonstrateFinallyBlock;
  
  WriteLn;
  
  // 5. 异常传播
  WriteLn('5. 异常传播:');
  DemonstrateExceptionPropagation;
  
  WriteLn;
  
  // 6. 异常信息显示
  WriteLn('6. 异常信息显示:');
  try
    raise EMathError.Create('数学计算错误示例');
  except
    on E: EMathError do
    begin
      WriteLn('    异常类名: ', E.ClassName);
      WriteLn('    异常消息: ', E.Message);
      WriteLn('    异常地址: ', IntToStr(PtrUInt(E.ExceptAddr)));
    end;
  end;
  
  WriteLn;
  WriteLn('演示了 Pascal 中异常处理的各种用法');
  
  // 等待用户按键，防止程序窗口立即关闭
  ReadLn;
end.